"""
统一配置管理模块
支持环境变量和配置文件，环境变量优先级更高
使用PyYAML库处理配置文件
"""

import os
from pathlib import Path
from typing import Dict, Any, Optional, List
from dataclasses import dataclass, field
import yaml


@dataclass
class LoggingConfig:
    """日志配置"""
    level: str = 'INFO'
    to_file: bool = False
    file_path: str = './logs/app.log'
    file_max_size: str = '10MB'
    file_backup_count: int = 5
    format: str = 'detailed'
    console_enabled: bool = True
    tree_debug_enabled: bool = True
    tree_debug_max_depth: int = 10
    tree_debug_max_nodes: int = 50
    tree_debug_token_display_length: int = 5
    tree_debug_show_hashes: bool = True


@dataclass
class ServiceDiscoveryConfig:
    """服务发现配置"""
    label_selector: List[str]
    namespace: str
    port_name: str
    inference_port: int
    refresh_interval: int  


@dataclass
class ZmqConfig:
    """ZMQ配置"""
    protocol: str = 'tcp'


class ConfigManager:
    """统一配置管理器"""
    
    # 环境变量映射
    ENV_MAPPING = {
        # 日志配置
        'LOG_LEVEL': 'logging.level',
        'LOG_TO_FILE': 'logging.to_file',
        'LOG_FILE_PATH': 'logging.file.path',
        'LOG_FILE_MAX_SIZE': 'logging.file.max_size',
        'LOG_FILE_BACKUP_COUNT': 'logging.file.backup_count',
        'LOG_FORMAT': 'logging.format',
        'LOG_CONSOLE_ENABLED': 'logging.console.enabled',
        
        # 服务发现配置
        'SERVICE_DISCOVERY_NAMESPACE': 'service_discovery.namespace',
        'SERVICE_DISCOVERY_LABEL_SELECTOR': 'service_discovery.label_selector',
        'SERVICE_DISCOVERY_PORT_NAME': 'service_discovery.port_name',
        'SERVICE_DISCOVERY_REFRESH_INTERVAL': 'service_discovery.refresh_interval',
        
        # ZMQ配置
        'ZMQ_PROTOCOL': 'zmq.protocol',
    }
    
    def __init__(self, config_file: Optional[str] = None):
        """
        初始化配置管理器
        :param config_file: 配置文件路径，默认为 config/application.yaml
        """
        self.config = {}
        
        # 加载配置文件
        if config_file is None:
            config_file = os.path.join(os.path.dirname(__file__), '..', '..', 'config', 'application.yaml')
        
        self._load_config_file(config_file)
        
        # 加载环境变量（优先级更高）
        self._load_env_vars()
    
    def _load_config_file(self, config_file: str):
        """从配置文件加载配置"""
        config_path = Path(config_file)
        if config_path.exists():
            try:
                with open(config_path, 'r', encoding='utf-8') as f:
                    file_config = yaml.safe_load(f)
                    if file_config:
                        self.config = file_config
            except Exception as e:
                # 配置文件加载失败时使用默认配置，但不抛出异常
                e.args
    
    def _load_env_vars(self):
        """从环境变量加载配置"""
        for env_key, config_key in self.ENV_MAPPING.items():
            env_value = os.getenv(env_key)
            if env_value is not None:
                self._set_nested_value(self.config, config_key, self._convert_env_value(env_value))
    
    @staticmethod
    def _convert_env_value(value: str) -> Any:
        """转换环境变量值为合适的类型"""
        # 布尔值转换
        if value.lower() in ('true', 'false'):
            return value.lower() == 'true'
        
        # 数字转换
        if value.isdigit():
            return int(value)
        
        # 字符串
        return value
    
    @staticmethod
    def _set_nested_value(config: Dict, key_path: str, value: Any):
        """设置嵌套字典的值"""
        keys = key_path.split('.')
        current = config
        
        for key in keys[:-1]:
            if key not in current:
                current[key] = {}
            current = current[key]
        
        current[keys[-1]] = value
    
    def _get_nested_value(self, key_path: str, default: Any = None) -> Any:
        """获取嵌套字典的值"""
        keys = key_path.split('.')
        current = self.config
        
        for k in keys:
            if isinstance(current, dict) and k in current:
                current = current[k]
            else:
                return default
        
        return current
    
    @staticmethod
    def _parse_size(size_str: str) -> int:
        """解析大小字符串为字节数"""
        size_str = size_str.upper().strip()
        
        try:
            if size_str.endswith('KB'):
                return int(size_str[:-2]) * 1024
            elif size_str.endswith('MB'):
                return int(size_str[:-2]) * 1024 * 1024
            elif size_str.endswith('GB'):
                return int(size_str[:-2]) * 1024 * 1024 * 1024
            else:
                # 默认为字节
                return int(size_str)
        except ValueError:
            # 解析失败时返回默认值 10MB
            return 10 * 1024 * 1024
    
    @property
    def logging(self) -> LoggingConfig:
        """获取日志配置"""
        return LoggingConfig(
            level=self._get_nested_value('logging.level', 'INFO').upper(),
            to_file=bool(self._get_nested_value('logging.to_file', False)),
            file_path=str(self._get_nested_value('logging.file.path', './logs/app.log')),
            file_max_size=str(self._get_nested_value('logging.file.max_size', '10MB')),
            file_backup_count=int(self._get_nested_value('logging.file.backup_count', 5)),
            format=str(self._get_nested_value('logging.format', 'detailed')),
            console_enabled=bool(self._get_nested_value('logging.console.enabled', True)),
            tree_debug_enabled=bool(self._get_nested_value('logging.tree_debug.enabled', True)),
            tree_debug_max_depth=int(self._get_nested_value('logging.tree_debug.max_depth', 10)),
            tree_debug_max_nodes=int(self._get_nested_value('logging.tree_debug.max_nodes', 50)),
            tree_debug_token_display_length=int(self._get_nested_value('logging.tree_debug.token_display_length', 5)),
            tree_debug_show_hashes=bool(self._get_nested_value('logging.tree_debug.show_hashes', True))
        )
    
    @property
    def service_discovery(self) -> ServiceDiscoveryConfig:
        """获取服务发现配置"""
        default_label_selector = ['pdtype=prefill', 'pdtype=aggregate']
        label_selector_value = self._get_nested_value(
            'service_discovery.label_selector', default_label_selector
        )
        if isinstance(label_selector_value, list):
            label_selector = [str(sel) for sel in label_selector_value]
        else:
            label_selector = default_label_selector
        
        return ServiceDiscoveryConfig(
            label_selector=label_selector,
            namespace=str(self._get_nested_value('service_discovery.namespace', 'ai-inference')),
            port_name=str(self._get_nested_value('service_discovery.port_name', 'zmq-pub')),
            inference_port=int(self._get_nested_value('service_discovery.inference_port', 8000)),
            refresh_interval=int(self._get_nested_value('service_discovery.refresh_interval', 10))
        )
    
    @property
    def zmq(self) -> ZmqConfig:
        """获取ZMQ配置"""
        return ZmqConfig(
            protocol=str(self._get_nested_value('zmq.protocol', 'tcp'))
        )
    
    def get_file_max_size_bytes(self) -> int:
        """获取日志文件最大大小（字节）"""
        return self._parse_size(self.logging.file_max_size)


# 全局配置实例
_config_manager = None


def get_config() -> ConfigManager:
    """获取全局配置管理器实例"""
    global _config_manager
    if _config_manager is None:
        _config_manager = ConfigManager()
    return _config_manager


def reload_config():
    """重新加载配置"""
    global _config_manager
    _config_manager = None